/**
 * Copyright (c) 2017-2018, zengjintao (1913188966@qq.com).
 * <p>
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jfast.framework.web.core;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.jetty.io.RuntimeIOException;

import com.jfast.framework.aop.InteceptorManager;
import com.jfast.framework.aop.Interceptor;
import com.jfast.framework.aop.annotation.InteceptorConfig;
import com.jfast.framework.job.JfastJobBuild;
import com.jfast.framework.job.JobBuild;
import com.jfast.framework.job.JobManger;
import com.jfast.framework.kit.StrKit;
import com.jfast.framework.log.Logger;
import com.jfast.framework.util.ClassFactory;
import com.jfast.framework.util.ClassScanner;
import com.jfast.framework.web.annotation.Controller;
import com.jfast.framework.web.annotation.HandlerConfig;
import com.jfast.framework.web.annotation.Plugin;
import com.jfast.framework.web.annotation.RequestMapping;
import com.jfast.framework.web.handler.ContextPathHandler;
import com.jfast.framework.web.handler.Handler;
import com.jfast.framework.web.handler.HandlerManager;
import com.jfast.framework.web.handler.JfastHandler;
import com.jfast.framework.web.orm.DataSourceFactory;
import com.jfast.framework.web.orm.config.DataSourceConfig;
import com.jfast.framework.web.orm.config.DataSourceConfigManager;
import com.jfast.framework.web.orm.config.DataSourceManager;
import com.jfast.framework.web.orm.config.DbConfig;
import com.jfast.framework.web.plugin.IPlugin;
import com.jfast.framework.web.plugin.PluginManager;


public class Config {
	
	private static final PluginManager pluginManger = PluginManager.getPluginManger();
	private static final InteceptorManager inteceptorManager = InteceptorManager.getInteceptorManager();
	private static List<Class<?>> controllerClass = new ArrayList<>();
	private static final Logger log = Logger.getLogger(Config.class);
	private static final Config config = new Config();
	private static final Map<String, Action> mapping = new HashMap<String, Action>();
	private static final HandlerManager handlerManager = HandlerManager.getHandlerManager();
	
	
	public static Config getConfig(){
		return config;
	}
	
	/**
	 * 初始化系统配置
	 */
	public void init(){
		initJfastConfig();
		initRequestMapping();
		initPlugins();
		initInteceptor();
		initHandler();
		startJob();
	}
	
	/**
	 * 启动系统job
	 */
	private void startJob() {
		List<Class<?>> jobList = ClassScanner.getClassByAnnoation(JobBuild.class);
		JobManger jobManger = JobManger.getJobManger();
		for (Class<?> clazz : jobList) {
			JfastJobBuild jfastBuild = (JfastJobBuild) ClassFactory.crateSingletonsBean(clazz);
			jobManger.addJfastBuild(jfastBuild);
		}
		new Thread(new Runnable() {
			@Override
			public void run() {
				jobManger.start();
			}
		}).start();
	}

	private void initHandler() {
		List<Class<?>> handlerClass = ClassScanner.getClassByAnnoation(HandlerConfig.class);
		for(Class<?> cla : handlerClass){
			handlerManager.add((Handler) ClassFactory.crateSingletonsBean(cla));
		}
		handlerManager.add(new ContextPathHandler());
		handlerManager.add(new JfastHandler());
	}

	/**
	 * 初始化Jfast配置
	 * @param jFastConfig
	 */
	private void initJfastConfig() {
		
		List<DataSourceConfig> dataSourceConfigs = DataSourceConfigManager.getDataSourceConfigManager().getDataSourceConfigs();
		
		//加载数据源配置
		for (DataSourceConfig dataSourceConfig : dataSourceConfigs) {
			DataSourceFactory dataSourceFactory = DataSourceManager.createDataSourceFactory(dataSourceConfig);
			DataSourceManager.add(new DbConfig(dataSourceFactory));
		}
	}
	
	
	/**
	 * 初始化拦截器
	 */
	private void initInteceptor() {
		List<Class<?>> clazzs = ClassScanner.getClassByAnnoation(InteceptorConfig.class);
		for(Class<?> cla : clazzs){
			Interceptor interceptor = (Interceptor) ClassFactory.crateSingletonsBean(cla);
			inteceptorManager.add(interceptor);
			log.debug("add Inteceptor '" + cla.getSimpleName()+"'");
		}
	}


	/**
	 * 初始化插件配置
	 */
	private void initPlugins() {
		List<Class<?>> clazzes = ClassScanner.getClassByAnnoation(Plugin.class);
		for (Class<?> clazz : clazzes) {
			try {
				IPlugin iPlugin = (IPlugin) ClassFactory.crateSingletonsBean(clazz);
				pluginManger.add(iPlugin);
			} catch (Exception e) {
				throw new RuntimeIOException("can not cast the class to IPlugin", e);
			}
		}
		List<IPlugin> plugins = pluginManger.getPlugins();
		for(IPlugin plugin : plugins){
			try {
				if(!plugin.start()){
					String message = "Plugin start error: " + plugin.getClass().getName();
					log.error(message);
					throw new RuntimeException(message);
				}
			} catch (Exception e) {
				String message = "Plugin start error: " + plugin.getClass().getName() + ". \n" + e.getMessage();
				log.error(message, e);
				throw new RuntimeException(message, e);
			}
		}
	}

	/**
	 * 初始化路由映射
	 */
	@SuppressWarnings({ "rawtypes","unchecked" })
	private void initRequestMapping() {
		List<Class<?>> classes = getControllerClass();
		RequestMapping requestMapping = null;
		for(Class cla : classes){
		    requestMapping = (RequestMapping) cla.getAnnotation(RequestMapping.class);
			String controllerKey = requestMapping == null ? "" : requestMapping.value();
			Method[] methods = cla.getDeclaredMethods();
			String actionKey = null;
			for(Method method : methods){
				requestMapping = method.getAnnotation(RequestMapping.class);
				if(requestMapping == null){
					actionKey = JfastConstant.SEPARATOR + StrKit.toLowerCaseFirst(method.getName());
				}else{
					actionKey = requestMapping.value();
				}
				
				if(StrKit.isNotEmpoty(controllerKey) && !controllerKey.equals("/")){
					actionKey = controllerKey + actionKey;
				}
				
//				if(actionKey.contains("{")){
//					actionKey = actionKey.substring(0, actionKey.indexOf("{") - 1);
//				}
				
				Action action = new Action(controllerKey,actionKey,method,cla);
				mapping.put(actionKey, action);
			}
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private List<Class<?>> getControllerClass() {
		List<Class<?>> classes = ClassScanner.getClassByAnnoation(Controller.class);
		for(Class cla : classes){
			Controller controller = (Controller) cla.getAnnotation(Controller.class);
			if(controller != null){
				controllerClass.add(cla);
			}
			continue;
		}
		return controllerClass;
	}

	public Action getAction(String url) {
		Action action = mapping.get(url);
		if (action != null) {
			return action;
		}
		
		return action;
	}
}
